/**
  ******************************************************************************
  * @file    mg_driver_sys.c
  * @author  
  * @version V1.1
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2019 Shanghai Macrogiga Electronics</center></h2>
  *
  ******************************************************************************
  */
#include "mg_driver_sys.h"
#include "mg_driver_int.h"



typedef struct
{
  __IO u32 CTRL;                    /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
  __IO u32 LOAD;                    /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register       */
  __IO u32 VAL;                     /*!< Offset: 0x008 (R/W)  SysTick Current Value Register      */
  __I  u32 CALIB;                   /*!< Offset: 0x00C (R/ )  SysTick Calibration Register        */
} SysTick_Type;

typedef struct
{
  __I  u32 CPUID;                   /*!< Offset: 0x000 (R/ )  CPUID Base Register                                   */
  __IO u32 ICSR;                    /*!< Offset: 0x004 (R/W)  Interrupt Control and State Register                  */
       u32 RESERVED0;
  __IO u32 AIRCR;                   /*!< Offset: 0x00C (R/W)  Application Interrupt and Reset Control Register      */
  __IO u32 SCR;                     /*!< Offset: 0x010 (R/W)  System Control Register                               */
  __IO u32 CCR;                     /*!< Offset: 0x014 (R/W)  Configuration Control Register                        */
       u32 RESERVED1;
  __IO u32 SHP[2];                  /*!< Offset: 0x01C (R/W)  System Handlers Priority Registers. [0] is RESERVED   */
  __IO u32 SHCSR;                   /*!< Offset: 0x024 (R/W)  System Handler Control and State Register             */
} SCB_Type;

#define SCS_BASE            (0xE000E000)      /*!< System Control Space Base Address */
#define SysTick_BASE        (SCS_BASE +  0x0010)
#define SCB_BASE            (SCS_BASE +  0x0D00UL)   /*!< System Control Block Base Address */
#define NVIC_IPR_BASE       (SCS_BASE +  0x0400UL)  /*!< IRQ IPR control base address */
#define NVIC_SETPEN_BASE    (SCS_BASE +  0x0200UL)  /*!< set pending irq base address */
#define NVIC_CLRPEN_BASE    (SCS_BASE +  0x0280UL)  /*!< clear pending irq base address */

#define SysTick             ((SysTick_Type *)SysTick_BASE)
#define SCB                 ((SCB_Type*) SCB_BASE)   /*!< SCB configuration struct*/

typedef struct _tagNVIC_IPR_
{
    __IO u32 IP[8];                /*!< irq priority setting control register  */
}NVIC_IPR_Type;

typedef struct _tagNVIC_SetPendingIRQ_
{
    __IO u32 reg;                /*!< clear pending irq register  */
}NVIC_SetIrq_Type;
typedef struct _tagNVIC_ClearPendingIRQ_
{
    __IO u32 reg;                /*!< clear pending irq register  */
}NVIC_ClearIrq_Type;

#define NVIC_IPR             ((NVIC_IPR_Type*) NVIC_IPR_BASE)  
#define NVIC_SET_PENDING_IRQ ((NVIC_SetIrq_Type*) NVIC_SETPEN_BASE) 
#define NVIC_CLR_PENDING_IRQ ((NVIC_ClearIrq_Type*) NVIC_CLRPEN_BASE) 

#define SysTick_CTRL_CLKSOURCE_Msk  0x00000004
#define SysTick_CTRL_TICKINT_Msk    0x00000002
#define SysTick_CTRL_ENABLE_Msk     0x00000001

/* SLEEPDEEP bit mask */
#define SysCtrl_SLEEPDEEP_Set    ((u32)0x00000004)


void SysTick_Init(u32 ticks /*24 bit*/)
{
  SysTick->LOAD  = ticks - 1;                                  /* set reload register */
//  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */
    
    NVIC_IrqSetPriority(0,1); //seg irq priority
    NVIC_IrqSetPriority(2,1); //bb irq priority, sys tick has the highest priority: -1.!!!
}

void NVIC_IrqSetPriority(u8 IrqIdx/*from 0 to max 31*/, u8 priority/*1,2,3*/)
{
    u32 value;
    
    if(IrqIdx > 31)return;
    
    value = NVIC_IPR->IP[IrqIdx >> 2];
    value &= (~(0xFF << ((IrqIdx&0x03) << 3)));
    value |= (priority << (((IrqIdx&0x03) << 3)+6));
    
    NVIC_IPR->IP[IrqIdx >> 2] = value;
}

void NVIC_IrqSetPendingIRQ(u8 IrqIdx/*from 0 to max 31*/)
{
    NVIC_SET_PENDING_IRQ->reg = (0x00000001 << IrqIdx);
}

void NVIC_IrqClearPendingIRQ(u8 IrqIdx/*from 0 to max 31*/)
{
    NVIC_CLR_PENDING_IRQ->reg = (0x00000001 << IrqIdx);
}

void SysGotoStopMode(void)
{
    SCB->SCR |= SysCtrl_SLEEPDEEP_Set;
    
    __wfi();
}

void SysGotoSleepMode(void) //It can work under non-SW debug mode ONLY!!!!
{
    SCB->SCR &= (~SysCtrl_SLEEPDEEP_Set);
    __wfi();
}

void SysGotoStandbyMode(void)
{
    SysCtrl->WKUP_SCAN_CTRL = 0x03; //enable wakeup source A0 and RTC if any, one may change this cfg.
    SysCtrl->PWR_CTRL = 0x20;
}

void Sys_StandaloneRegWrite(u8 Idx, u32 Value)
{
    if(Idx < 2) SYS_STDALONE_REG->Reg[Idx] = Value;
}

u32  Sys_StandaloneRegRead(u8 Idx)
{
    if(Idx < 2)return SYS_STDALONE_REG->Reg[Idx];
    
    return 0;
}

void Sys_SetRomWakeupDelay(u32 delay)
{
    SYS_ROM_WAKEUP_DELAY_REG->Reg = delay;
}

void Sys_SpiSelect(u8 InternalEnableFlag/*default 0*/)
{
    u8 t;
    t = SYS_PIN_SELECT_REG->Reg & 0xFE;
    SYS_PIN_SELECT_REG->Reg = t | InternalEnableFlag;
//    SYS_PIN_SELECT_REG->Reg = t | InternalEnableFlag | 0x04/*output 16Mhz*/;
}

void Sys_ClockOutEnable(u8 McoEnClkID/*default 0*/)
{
    u8 t;
    t = SYS_PIN_SELECT_REG->Reg & (~MCO_MASKBIT);
    
    t |= McoEnClkID;
    
    SYS_PIN_SELECT_REG->Reg = t;
}

void Sys_EnableCachePowerOff(u8 EnableFlag/*default 0*/)
{
    u8 t;
    t = SYS_PIN_SELECT_REG->Reg & (0xF7);
    
    if(EnableFlag) t |= CACHE_PWR_OFF_EN;
    
    SYS_PIN_SELECT_REG->Reg = t;
}

void Sys_SpiCsEnable(void)
{
    SYS_SPI_CS->Reg = 0;
}

void Sys_SpiCsDisable(void)
{
    SYS_SPI_CS->Reg = 1;
}
